package com.michael.demos.base.thread.juc.lock;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 类功能描述:
 * <pre>
 *   JAVA 自带可重入锁使用示例
 * </pre>
 *
 * @author Michael
 * @version 1.0
 * @date 2020/8/14 14:37
 */
public class NativeReentrantLockDemo {

	/** 默认为不公平锁 */
	private static ReentrantLock lock = new ReentrantLock();

	/** 公平锁的初始化 */
//	private static ReentrantLock fairLock = new ReentrantLock(true);
	public static void main(String[] args) {
//		testJustDoOnce();
//		testDoItOneByOne();
//		testDoItInTime();
		testCanBeInterrupt();
	}

	public static void testJustDoOnce() {

		int threadCount = 500;

		CountDownLatch countDownLatch = new CountDownLatch(threadCount);
		ExecutorService threadPool = Executors.newFixedThreadPool(threadCount);

		for (int i = 0; i < threadCount; i++) {
			threadPool.submit(() -> {
				try {
					justDoOnce();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				countDownLatch.countDown();
			});
		}

		try {
			countDownLatch.await();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

		System.out.println("testJustDoOnce():结束执行");
		threadPool.shutdown();
	}

	public static void testDoItOneByOne() {

		int threadCount = 5;

		CountDownLatch countDownLatch = new CountDownLatch(threadCount);
		ExecutorService threadPool = Executors.newFixedThreadPool(threadCount);

		for (int i = 0; i < threadCount; i++) {
			int finalI = i;
			threadPool.submit(() -> {
				try {
					Thread.currentThread().setName("第" + finalI + "号线程：");
					doItOneByOne();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				countDownLatch.countDown();
			});
		}

		try {
			countDownLatch.await();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

		System.out.println("testDoItOneByOne():结束执行");
		threadPool.shutdown();
	}

	public static void testDoItInTime() {

		int threadCount = 5;

		CountDownLatch countDownLatch = new CountDownLatch(threadCount);
		ExecutorService threadPool = Executors.newFixedThreadPool(threadCount);

		for (int i = 0; i < threadCount; i++) {
			int finalI = i;
			threadPool.submit(() -> {
				try {
					Thread.currentThread().setName("第" + finalI + "号线程：");
					doItInTime();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				countDownLatch.countDown();
			});
		}

		try {
			countDownLatch.await();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

		System.out.println("testDoItInTime():结束执行");
		threadPool.shutdown();
	}

	public static void testCanBeInterrupt() {

		Thread t1 = new Thread(() -> {
			try {
				canBeInterrupt();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		});
		Thread t2 = new Thread(() -> {
			try {
				canBeInterrupt();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		});

		t1.setName("线程A:");
		t2.setName("线程B:");

		t1.start();
		t2.start();

		try {
			TimeUnit.SECONDS.sleep(1L);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		t1.interrupt();
	}

	/** 使用场景：如果发现该操作已经在执行中则不再执行（有状态执行） */
	public static void justDoOnce() throws InterruptedException {
		if (lock.tryLock()) {
			try {
				System.out.println("我在办事，我只会执行一次");
				TimeUnit.SECONDS.sleep(1L);
			} finally {
				lock.unlock();
			}
		}
	}

	/** 使用场景：如果发现该操作已经在执行，等待一个一个执行（同步执行，类似synchronized） */
	public static void doItOneByOne() throws InterruptedException {
		lock.lock();
		try {
			String name = Thread.currentThread().getName();
			System.out.println(name + "我在办事，这次要排好队一个个来");
			TimeUnit.SECONDS.sleep(1L);
		} finally {
			lock.unlock();
		}
	}

	/** 使用场景：如果发现该操作已经在执行，则尝试等待一段时间，等待超时则不执行（尝试等待执行） */
	public static void doItInTime() throws InterruptedException {
		try {
			String name = Thread.currentThread().getName();
			System.out.println(name + "我准备办事，就等2秒，过时不候...");
			if (lock.tryLock(2, TimeUnit.SECONDS)) {
				try {
					System.out.println(name + "我在办事了");
					TimeUnit.SECONDS.sleep(1L);
				} finally {
					lock.unlock();
				}
			}
		} catch (InterruptedException e) {
			// 当前线程被中断，会出这个异常
			e.printStackTrace();
		}
	}

	/** 使用场景：如果发现该操作已经在执行，等待执行。这时可中断正在进行的操作立刻释放锁继续下一操作 */
	public static void canBeInterrupt() throws InterruptedException {
		String name = Thread.currentThread().getName();
		try {
			lock.lockInterruptibly();
			System.out.println(name + "开始干活");
			TimeUnit.SECONDS.sleep(3L);
			System.out.println(name + "活干完了");
		} catch (InterruptedException e) {
			System.out.println(name + "我被打断了");
		} finally {
			lock.unlock();
		}

	}
}
